home *** CD-ROM | disk | FTP | other *** search
/ Aminet 40 / Aminet 40 (2000)(Schatztruhe)[!][Dec 2000].iso / Aminet / dev / c / ExtrasLib.lha / ExtrasLib / Source / Thread.c < prev    next >
Encoding:
C/C++ Source or Header  |  2000-09-30  |  12.6 KB  |  545 lines

  1. #include <extras/threads.h>
  2. #include <clib/extras/thread_protos.h>
  3.  
  4. #include <dos.h>
  5. #include <strings.h>
  6.  
  7. //#define DEBUG
  8. #include <debug.h>
  9.  
  10. #include <clib/alib_protos.h>
  11.  
  12. #include <dos/dos.h>
  13. #include <dos/dostags.h>
  14. #include <exec/memory.h>
  15.  
  16. #include <proto/dos.h>
  17. #include <proto/exec.h>
  18. #include <proto/utility.h>
  19.  
  20. ULONG my_AToI(STRPTR Str);
  21.  
  22. /* internal use */
  23. struct InitThread
  24. {
  25.   struct Task *it_CreaterTask;
  26.   BYTE it_Signal;
  27.   BYTE it_RetVal;
  28.   struct Library *it_ModuleBase;
  29.   struct Thread *it_Thread;
  30.   void __asm (*it_MsgHandler)(register __a0 struct Thread *T,
  31.                               register __a1 struct ThreadMessage *Msg);
  32. };
  33.  
  34. void SingleMsgPort(struct MsgPort *MP);
  35. void __asm __saveds ThreadEntry(register __a0 STRPTR Args);
  36. void __asm __saveds ThreadSubEntry(register __a0 struct InitThread *it,
  37.                                    register __a6 APTR LibBase);
  38.  
  39. struct ThreadMessage *InThreadGetMsg(struct Thread *T);          // Used by message to get messages for thread
  40.  
  41. /****** extras.lib/thread_StartThread ******************************************
  42. *
  43. *   NAME
  44. *       thread_StartThread -- Create a thread.
  45. *
  46. *   SYNOPSIS
  47. *       Thread thread_StartThread(Tags)
  48. *
  49. *       struct Thread *thread_StartThread(Tag, ... );
  50. *
  51. *   FUNCTION
  52. *       Creates and starts a new thread (Process).
  53. *
  54. *   INPUTS
  55. *       Tags - TagList (on stack)
  56. *         TA_Name - Name of thread, defaults to "Thread".
  57. *         TA_Stack - Stacksize, default 8192.
  58. *         TA_Priority - default -1
  59. *         TA_MsgHandler - Function to handle thread messages.
  60. *         TA_UserData - (APTR)
  61. *         TA_A6 - (struct Library *) 
  62. *
  63. *   RESULT
  64. *       Pointer to the newly created Thread, or NULL on failure.
  65. *       The Thread stucture is ReadOnly, except for
  66. *         t_Node, UserData and ThreadData
  67. *
  68. *   NOTES
  69. *       It's suggested that ThreadData be used store local data
  70. *       for the Thread.
  71. *
  72. *   BUGS
  73. *       1.3 - Made functional, some timing issues caused crashes.
  74. *
  75. *   SEE ALSO
  76. *
  77. ******************************************************************************
  78. *
  79. */
  80.  
  81. struct Thread *thread_StartThread(ULONG Tags, ... )
  82. {
  83.   struct TagItem *tl;
  84.   struct Thread *thread;
  85.   struct Process *proc=0;
  86.   struct InitThread *init;
  87.   UBYTE initaddr[11];
  88.   BPTR input,output=0;
  89.   BYTE sigbit;   
  90.   APTR func;
  91.  
  92.   thread=0;
  93.   tl=(APTR)&Tags;
  94.  
  95. DKP("1\n");
  96.  
  97.   if(func=(APTR)GetTagData(TA_MsgHandler, 0, tl))
  98.   {
  99. DKP("2\n");
  100.     if(thread=AllocVec(sizeof(*thread),MEMF_CLEAR|MEMF_PUBLIC))
  101.     {
  102. DKP("3\n");
  103.       thread->UserData=(APTR)GetTagData(TA_UserData, 0, tl);
  104.       
  105.       if((sigbit=AllocSignal(-1))!=-1)
  106.       {
  107. DKP("4\n");
  108.         if(init=AllocVec(sizeof(struct InitThread),MEMF_PUBLIC|MEMF_CLEAR))
  109.         {
  110. DKP("5\n");
  111.           init->it_CreaterTask  =FindTask(0);
  112.           init->it_Signal      =sigbit;
  113.           init->it_ModuleBase  =(struct Library *)getreg(REG_A6);  
  114.           init->it_Thread      =thread;
  115.           init->it_MsgHandler  =func;
  116.           
  117.  //         init->it_A6           =GetTagData(TA_A6, 0, tl))
  118.     
  119.           stci_d(initaddr,(LONG)init);
  120. DKP("6  DosBase = %lx\n", DOSBase);           
  121.  
  122.           if(DOSBase)
  123.           {   
  124.             if(input=Open((STRPTR)"NIL:",MODE_OLDFILE))
  125.             {
  126.   DKP("7\n");
  127.               if(output=Open((STRPTR)"NIL:",MODE_NEWFILE))
  128.               {
  129.                 DKP("Creating Proc\n");
  130.       
  131.                 if(proc=CreateNewProcTags(NP_Input         ,input,
  132.                                           NP_Output        ,output,
  133.                                           NP_Entry         ,ThreadEntry,
  134.                                           NP_Name          ,GetTagData(TA_Name,           (ULONG)"Thread", tl),
  135.                                           NP_StackSize     ,GetTagData(TA_Stack,          8192,           tl),
  136.                                           NP_Arguments     ,initaddr,
  137.                                           NP_Priority      ,GetTagData(TA_Priority,       -1,             tl),
  138.                                           TAG_DONE))
  139.                 {
  140.                   DKP("Proc Created - Waiting for Signal  it=%8lx a6=%8lx\n",init,init->it_ModuleBase);
  141.                   Wait(1<<sigbit);
  142.                   DKP("Signaled  RetVal=%ld\n",init->it_RetVal);
  143.                   if(!init->it_RetVal)
  144.                     proc=0;
  145.                 }
  146.               }
  147.             }
  148.             if(!proc)
  149.             {
  150.               if(input)
  151.                 Close(input);
  152.               if(output)
  153.                 Close(output);
  154.             }
  155.           }
  156.           FreeVec(init);
  157.         }
  158.         FreeSignal(sigbit);
  159.       }
  160.       if(!thread->t_Process)
  161.       {
  162.         FreeVec(thread);
  163.         thread=0;
  164.       }
  165.     }
  166.   }
  167. //  DKP("Leaving CreateInput\n");
  168.   return(thread);
  169. }      
  170.  
  171. /****** extras.lib/thread_EndThread ******************************************
  172. *
  173. *   NAME
  174. *       thread_EndThread -- end a thread.
  175. *
  176. *   SYNOPSIS
  177. *
  178. *
  179. *
  180. *
  181. *
  182. *
  183. *   FUNCTION
  184. *
  185. *
  186. *   INPUTS
  187. *
  188. *   RESULT
  189. *
  190. *   EXAMPLE
  191. *
  192. *   NOTES
  193. *       Note, this function waits for a reply.
  194. *
  195. *   BUGS
  196. *
  197. *   SEE ALSO
  198. *
  199. ******************************************************************************
  200. *
  201. */
  202.  
  203.  
  204. void thread_EndThread(struct Thread *Thread, APTR NullForNow)
  205. {
  206.   struct ThreadMessage diemsg;
  207.   struct Message *cm;
  208.   struct MsgPort mp;
  209.  
  210.   if(Thread)
  211.   {
  212.     SingleMsgPort(&mp);
  213.   
  214.     diemsg.tm_Msg.mn_ReplyPort     =∓
  215.     diemsg.tm_Msg.mn_Length        =sizeof(diemsg);
  216.     diemsg.tm_Command              =TMSG_DIE;
  217.     
  218.     if(Thread->t_MsgPort)
  219.     {
  220.       PutMsg(Thread->t_MsgPort,(struct Message *)&diemsg);
  221. //      WaitForReply(&diemsg);
  222.       while((cm=GetMsg(&mp))!=&diemsg)
  223.       {
  224.         WaitPort(&mp);
  225.       }
  226.     }
  227.     FreeVec(Thread);
  228.   }
  229. }
  230.  
  231. void SingleMsgPort(struct MsgPort *MP)
  232. {
  233.   MP->mp_Flags=PA_SIGNAL;
  234.   MP->mp_SigBit=SIGF_SINGLE; 
  235.   MP->mp_SigTask=FindTask(0);
  236.   NewList(&MP->mp_MsgList);
  237. }
  238.  
  239. /* Meat & Potatoes */
  240.  
  241. void __asm __saveds ThreadEntry(register __a0 STRPTR Args)
  242. {
  243.   struct InitThread *it;
  244.   
  245.   it=(struct InitThread *)my_AToI(Args);
  246.  
  247.   ThreadSubEntry(it,it->it_ModuleBase);
  248. }
  249.  
  250. void __asm __saveds ThreadSubEntry(register __a0 struct InitThread *it,
  251.                                    register __a6 APTR LibBase)
  252. {
  253.   struct MsgPort *mp;
  254.   struct Thread *me;
  255.   struct ThreadMessage *diemsg=0;
  256.   ULONG   isig,allsigs,sig; 
  257.   BOOL    go=TRUE;
  258.   void __asm (*MsgHandler)(register __a0 struct Thread *T,
  259.                            register __a1 struct ThreadMessage *Msg,
  260.                            register __a6 APTR LibBase);
  261.  
  262.   if(mp=CreateMsgPort())
  263.   {
  264.     isig=1<<mp->mp_SigBit;
  265.  
  266.     me=it->it_Thread;    
  267.     it->it_Thread->t_MsgPort = mp;
  268.     it->it_Thread->t_Process = (struct Process *)FindTask(0);
  269.     MsgHandler=it->it_MsgHandler;
  270.  
  271.     it->it_RetVal=1;  /* Signal creator */
  272.     Signal(it->it_CreaterTask,1<<it->it_Signal);
  273.  
  274.     it=0;  /* don't want to signal again, see below */
  275.  
  276.     allsigs=isig;
  277.     while(go)
  278.     {
  279. //      DKP("Waiting for %8lx\n",allsigs);
  280.       
  281. //      sig=Wait(allsigs);
  282.       sig=Wait(-1);
  283. //      DKP("Signal recieved %8lx\n",sig);
  284.       
  285.       if(sig & isig)
  286.       {
  287. //        DKP("Message signal recieved\n");
  288.         while(me->t_CurrentMsg=(struct ThreadMessage *)GetMsg(mp))
  289.         {
  290. //          DKP("Msg @ 0x%08lx\n",msg);
  291.           switch(me->t_CurrentMsg->tm_Command)
  292.           {
  293.             case TMSG_DIE:
  294.               MsgHandler(me,me->t_CurrentMsg,LibBase);
  295.               diemsg=me->t_CurrentMsg;
  296.               me->t_CurrentMsg=0;
  297.               go=0;
  298.               break;
  299.             default:
  300.               MsgHandler(me,me->t_CurrentMsg,LibBase);
  301.               break;
  302.           }
  303.           if(me->t_CurrentMsg)
  304.             ReplyMsg((APTR)me->t_CurrentMsg);
  305.         }
  306.       }
  307.       
  308.       if(sig & ~(isig))
  309.       {
  310.         struct TMsg_Signal tms;
  311.         
  312.         tms.TMsg.tm_Msg.mn_Length=sizeof(tms);
  313.         tms.TMsg.tm_Command=TMSG_SIGNAL;
  314.         tms.Signal=sig;
  315.         
  316.         MsgHandler(me,(APTR)&tms,LibBase);
  317.       }
  318.       
  319.     }
  320.     DeleteMsgPort(mp);  
  321.   }
  322.   
  323.   if(it)
  324.   {
  325.     it->it_RetVal=0;  /* Signal creator */
  326.     Signal(it->it_CreaterTask,1<<it->it_Signal);
  327.   }
  328.   
  329.   Disable();
  330.   
  331.   if(diemsg)
  332.     ReplyMsg((struct Message *)diemsg);
  333. }
  334.  
  335. ULONG my_AToI(STRPTR Str)
  336. {
  337.   ULONG i=0;
  338.   
  339.   while(*Str>'9' || *Str<'0' && *Str)
  340.     Str++;
  341.   
  342.   while(*Str<='9' && *Str>='0')
  343.   {
  344.     i=(i*10)+((*Str)-'0');
  345.     Str++;
  346.   }
  347.   return(i);
  348. }
  349.  
  350. /****** extras.lib/thread_PutTMsg ******************************************
  351. *
  352. *   NAME
  353. *       thread_PutTMsg --
  354. *
  355. *   SYNOPSIS
  356. *       success=thread_PutTMsg(Thread, Msg)
  357. *
  358. *       BOOL thread_PutTMsg(struct Thread *, struct ThreadMessage *)
  359. *
  360. *   FUNCTION
  361. *       Send a message to the thread, this function does not
  362. *       wait for a reply.  You must supply a reply port for
  363. *       your message.
  364. *
  365. *   INPUTS
  366. *       Thread - to send message to
  367. *       Msg - Message to send.
  368. *
  369. *   RESULT
  370. *       Non-zero if message successfully sent.     
  371. *
  372. *   NOTES
  373. *       Note, this function does not wait for a reply.
  374. *
  375. ******************************************************************************
  376. *
  377. */
  378.  
  379.  
  380. BOOL thread_PutTMsg(struct Thread *Thread, struct ThreadMessage *TM)
  381. {
  382.   if(Thread)
  383.   {
  384.     if(Thread->t_MsgPort)
  385.     {
  386.       PutMsg(Thread->t_MsgPort,(struct Message *)TM);
  387.       return(1);
  388.     }
  389.   }
  390.   return(0);
  391. }
  392.  
  393.  
  394. /****** extras.lib/thread_PutTMsg_TagList ******************************************
  395. *
  396. *   NAME
  397. *       thread_PutTMsg_TagList -- Send a TagListTMsg to a thread (varargs)
  398. *
  399. *   SYNOPSIS
  400. *       RetVal = thread_PutTMsg_TagList(Thread, Command, Tags ... )
  401. *
  402. *       ULONG thread_PutTMsg_TagList(struct Thread, ULONG, Tag, ...);
  403. *
  404. *   FUNCTION
  405. *       Sends a message to the task, using the TMsg_TagList structure.
  406. *       Waits for a reply, then returns tm_RetVal.
  407. *
  408. *   INPUTS
  409. *       Thread - (struct Thread *)
  410. *       Command - Command ID.
  411. *       Tag - 
  412. *
  413. *   RESULT
  414. *       returns zero on failure, otherwise returns value of TMsg_TagList.tm_RetVal.
  415. *
  416. *   NOTES
  417. *       Note, this function waits for a reply.
  418. *
  419. ******************************************************************************
  420. *
  421. */
  422.  
  423.  
  424. ULONG thread_PutTMsg_TagList(struct Thread *Thread, ULONG Command, ULONG Tag, ...)
  425. {
  426.   struct TMsg_TagList msg;
  427.   struct MsgPort mp;
  428.  
  429.   if(Thread)
  430.   {
  431.     SingleMsgPort(&mp);
  432.   
  433.     msg.tm_Msg.mn_ReplyPort     =∓
  434.     msg.tm_Msg.mn_Length        =sizeof(msg);
  435.     msg.tm_Command              =Command;
  436.     msg.tm_TagList              =(APTR)&Tag;
  437.     
  438.     if(Thread->t_MsgPort)
  439.     {
  440.       PutMsg(Thread->t_MsgPort,(struct Message *)&msg);
  441. //      WaitForReply(&diemsg);
  442.  
  443.       while(&msg!=(APTR)GetMsg(&mp))
  444.       {
  445.         WaitPort(&mp);
  446.       }
  447.       return(msg.tm_RetVal);
  448.     }
  449.   }
  450.   return(0);
  451. }
  452.  
  453.  
  454. /****** extras.lib/thread_PutTMsg_Sync ******************************************
  455. *
  456. *   NAME
  457. *       thread_PutTMsg_Sync -- Send a ThreadMessage to a thread.
  458. *
  459. *   SYNOPSIS
  460. *       success=thread_PutTMsg_Sync(Thread, Msg)
  461. *
  462. *       BOOL thread_PutTMsg_Sync(Thread, struct ThreadMessage);
  463. *
  464. *   FUNCTION
  465. *       Send a message to the thread, this function will
  466. *       wait for a reply.  The messages reply port will be changed.
  467. *
  468. *   INPUTS
  469. *       Thread - to send message to
  470. *       Msg - Message to send.
  471. *
  472. *   RESULT
  473. *       Non-zero if message successfully sent.
  474. *
  475. *   NOTES
  476. *       Note, this function waits for a reply.
  477. *       replyport is changed
  478. *
  479. *   BUGS
  480. *
  481. *   SEE ALSO
  482. *
  483. ******************************************************************************
  484. *
  485. */
  486.  
  487.  
  488. BOOL thread_PutTMsg_Sync(struct Thread *Thread, struct ThreadMessage *TMsg)//                         (1.3.1) (08/20/00)
  489. {
  490.   struct MsgPort mp;
  491.  
  492.   if(Thread)
  493.   {
  494.     SingleMsgPort(&mp);
  495.   
  496.     TMsg->tm_Msg.mn_ReplyPort     =∓
  497.     
  498.     if(Thread->t_MsgPort)
  499.     {
  500.       PutMsg(Thread->t_MsgPort,(struct Message *)TMsg);
  501.  
  502.       while(TMsg!=(APTR)GetMsg(&mp))
  503.       {
  504.         WaitPort(&mp);
  505.       }
  506.       TMsg->tm_Msg.mn_ReplyPort     =0;
  507.       return(1);
  508.     }
  509.     TMsg->tm_Msg.mn_ReplyPort     =0;
  510.   }
  511.   return(0);
  512. }
  513.  
  514. /****** extras.lib/thread_ReplyCurrentMsg ******************************************
  515. *
  516. *   NAME
  517. *       thread_ReplyCurrentMsg -- replies the current ThreadMessage.
  518. *
  519. *   SYNOPSIS
  520. *       thread_ReplyCurrentMsg(Thread)
  521. *
  522. *   FUNCTION
  523. *       Replies the current ThreadMessage, only to be called from inside
  524. *       the thread MsgHandler.  This may allow tasks waiting for a reply
  525. *       while the MsgHandler processes the message.
  526. *
  527. *   INPUTS
  528. *       The thread.
  529. *
  530. *   NOTE
  531. *       You must cache the message data, once you reply the message,
  532. *       that message data may no longer be valid..
  533. *
  534. *
  535. ******************************************************************************
  536. *
  537. */
  538.  
  539.  
  540. void thread_ReplyCurrentMsg(struct Thread *Thread)//                                                   (1.4.1) (08/24/00)
  541. {
  542.   ReplyMsg(Thread->t_CurrentMsg);
  543.   Thread->t_CurrentMsg=0;
  544. }
  545.